/*
 * TabuleiroBit.cpp
 *
 *  Created on: 21/09/2011
 *      Author: enikolas
 */

#include "tipos.h"
#include "TabuleiroBit.h"

using namespace GoKnightEnum;

TabuleiroBit::TabuleiroBit() {

	this->linha[LINHA_1] = 0x00000000000000FFULL;
	this->coluna[COLUNA_A] = 0x0101010101010101ULL;

	this->setMask[A1] = 0x1LL;
	this->clearMask[A1] = ~this->setMask[A1];

	for(int i = B1; i <= H8; i++) {
		this->setMask[i] = this->setMask[A1] << i;
		this->clearMask[i] = ~this->setMask[i];
	}

	for(int i = 1; i < NUM_LINHAS_COLUNAS; i++) {
		this->coluna[i] = this->coluna[COLUNA_A] << i;
		this->linha[i] = this->linha[LINHA_1] << i*8;
	}

	//Calcula as maskaras de atack do cavalo
	int cavaloAtk[8] = { 6, 15, 17, 10, -6, -15, -17, -10 };
	for(int linha=LINHA_1; linha<=LINHA_8; linha++) {
		for(int col=COLUNA_A; col<=COLUNA_H; col++) {
			int casa = obtemCasa(Coluna(col),Linha(linha));

			this->maskAttack[CAVALO][casa] = 0;

			for(int i=0; i<8; i++){
				int casaAlvo = casa + cavaloAtk[i];
				if(casaAlvo >= 0 && casaAlvo <=63) {
					int linhaAlvo = casaAlvo / 8;
					int colunaAlvo = casaAlvo % 8;
					if(abs(linha-linhaAlvo)<=2 && abs(col-colunaAlvo)<=2) {
						this->maskAttack[CAVALO][casa] |= this->setMask[casaAlvo];
					}
				}
			}
		}
	}
}

tipoTabuleiro TabuleiroBit::setBit(tipoTabuleiro tabuleiro, Casa casa) {
	return tabuleiro | this->setMask[casa];
}

tipoTabuleiro TabuleiroBit::clearBit(tipoTabuleiro tabuleiro, Casa casa) {
	return tabuleiro & this->clearMask[casa];
}

bool TabuleiroBit::isBitSet(tipoTabuleiro tabuleiro, Casa casa) {
	return (tabuleiro & this->setMask[casa]) != 0;
}

bool TabuleiroBit::isBitClear(tipoTabuleiro tabuleiro, Casa casa) {
	return (tabuleiro & this->setMask[casa]) == 0;
}

Casa TabuleiroBit::obtemCasa(Coluna coluna, Linha linha) {
	return Casa(int(linha)*8+int(coluna));
}

int TabuleiroBit::popCount(tipoTabuleiro tabuleiro) {
	if(!tabuleiro) {
		return 0;
	} else if(tabuleiro & (tabuleiro-1)) {
		return 1;
	} else {
		tabuleiro -= ((tabuleiro >> 1) & 0x5555555555555555ULL);
		tabuleiro = (tabuleiro & 0x3333333333333333ULL) + ((tabuleiro >> 2) & 0x3333333333333333ULL);
		tabuleiro = (tabuleiro + (tabuleiro >> 4)) & 0x0f0f0f0f0f0f0f0fULL;
		tabuleiro = (tabuleiro * 0x0101010101010101ULL) >> 56;
	}
	return int(tabuleiro);
}

void TabuleiroBit::printTabuleiro(tipoTabuleiro tabuleiro) {
	using namespace std;

	for( int linha = LINHA_8; linha >= LINHA_1; linha--) {
		cout << "+---+---+---+---+---+---+---+---+" << endl;
		for( int coluna = COLUNA_A; coluna <= COLUNA_H; coluna++) {
			cout << "| " << this->isBitSet(tabuleiro, obtemCasa(Coluna(coluna),Linha(linha))) << " ";
		}
		cout << "|" << endl;
	}
	cout << "+---+---+---+---+---+---+---+---+" << endl << endl;
}
